"""
目录扫描器基类

定义目录扫描和文件分类的通用接口和数据结构。
"""

from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional, Set, Callable
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from enum import Enum
import json


class FileType(Enum):
    """文件类型枚举"""
    VIDEO = "video"
    AUDIO = "audio"
    IMAGE = "image"
    DOCUMENT = "document"
    ARCHIVE = "archive"
    UNKNOWN = "unknown"


class FileCategory(Enum):
    """文件分类枚举"""
    PRODUCT_DISPLAY = "product_display"      # 产品展示
    PRODUCT_USAGE = "product_usage"          # 产品使用
    MODEL_WEARING = "model_wearing"          # 模特试穿
    AI_GENERATED = "ai_generated"            # AI素材
    UNCLASSIFIED = "unclassified"           # 未分类
    BACKGROUND = "background"                # 背景素材
    PROMOTIONAL = "promotional"              # 宣传素材


@dataclass
class FileInfo:
    """文件信息"""
    
    # 基本信息
    path: str = ""
    name: str = ""
    size: int = 0
    created_time: Optional[datetime] = None
    modified_time: Optional[datetime] = None
    
    # 文件类型
    file_type: FileType = FileType.UNKNOWN
    extension: str = ""
    mime_type: str = ""
    
    # 分类信息
    category: FileCategory = FileCategory.UNCLASSIFIED
    confidence: float = 0.0
    tags: List[str] = field(default_factory=list)
    
    # 元数据
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    # 处理状态
    is_processed: bool = False
    processing_errors: List[str] = field(default_factory=list)
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        result = {}
        for key, value in self.__dict__.items():
            if isinstance(value, (FileType, FileCategory)):
                result[key] = value.value
            elif isinstance(value, datetime):
                result[key] = value.isoformat() if value else None
            else:
                result[key] = value
        return result
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'FileInfo':
        """从字典创建"""
        # 处理枚举字段
        if 'file_type' in data and isinstance(data['file_type'], str):
            data['file_type'] = FileType(data['file_type'])
        
        if 'category' in data and isinstance(data['category'], str):
            data['category'] = FileCategory(data['category'])
        
        # 处理datetime字段
        for time_field in ['created_time', 'modified_time']:
            if time_field in data and data[time_field]:
                if isinstance(data[time_field], str):
                    data[time_field] = datetime.fromisoformat(data[time_field])
        
        return cls(**data)


@dataclass
class ClassificationRule:
    """分类规则"""
    
    name: str = ""
    description: str = ""
    category: FileCategory = FileCategory.UNCLASSIFIED
    
    # 规则条件
    file_patterns: List[str] = field(default_factory=list)  # 文件名模式
    path_patterns: List[str] = field(default_factory=list)  # 路径模式
    size_range: Optional[tuple] = None  # 文件大小范围 (min, max)
    
    # 元数据条件
    metadata_conditions: Dict[str, Any] = field(default_factory=dict)
    
    # 规则权重和优先级
    priority: int = 0
    confidence_boost: float = 0.0
    
    # 自定义条件函数
    custom_condition: Optional[Callable[[FileInfo], bool]] = None
    
    def matches(self, file_info: FileInfo) -> bool:
        """检查文件是否匹配规则"""
        import fnmatch
        
        # 检查文件名模式
        if self.file_patterns:
            name_match = any(fnmatch.fnmatch(file_info.name.lower(), pattern.lower()) 
                           for pattern in self.file_patterns)
            if not name_match:
                return False
        
        # 检查路径模式
        if self.path_patterns:
            path_match = any(fnmatch.fnmatch(file_info.path.lower(), pattern.lower()) 
                           for pattern in self.path_patterns)
            if not path_match:
                return False
        
        # 检查文件大小
        if self.size_range:
            min_size, max_size = self.size_range
            if not (min_size <= file_info.size <= max_size):
                return False
        
        # 检查元数据条件
        for key, expected_value in self.metadata_conditions.items():
            if key not in file_info.metadata:
                return False
            
            actual_value = file_info.metadata[key]
            if isinstance(expected_value, dict):
                # 支持范围条件
                if 'min' in expected_value and actual_value < expected_value['min']:
                    return False
                if 'max' in expected_value and actual_value > expected_value['max']:
                    return False
            else:
                if actual_value != expected_value:
                    return False
        
        # 检查自定义条件
        if self.custom_condition and not self.custom_condition(file_info):
            return False
        
        return True


@dataclass
class ScanResult:
    """扫描结果"""
    
    # 扫描信息
    scan_path: str = ""
    scan_time: Optional[datetime] = None
    scan_duration: float = 0.0
    
    # 文件统计
    total_files: int = 0
    processed_files: int = 0
    error_files: int = 0
    
    # 文件列表
    files: List[FileInfo] = field(default_factory=list)
    
    # 分类统计
    category_stats: Dict[str, int] = field(default_factory=dict)
    type_stats: Dict[str, int] = field(default_factory=dict)
    
    # 错误信息
    errors: List[str] = field(default_factory=list)
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "scan_path": self.scan_path,
            "scan_time": self.scan_time.isoformat() if self.scan_time else None,
            "scan_duration": self.scan_duration,
            "total_files": self.total_files,
            "processed_files": self.processed_files,
            "error_files": self.error_files,
            "files": [f.to_dict() for f in self.files],
            "category_stats": self.category_stats,
            "type_stats": self.type_stats,
            "errors": self.errors
        }
    
    def save_to_file(self, output_path: str) -> None:
        """保存到文件"""
        with open(output_path, 'w', encoding='utf-8') as f:
            json.dump(self.to_dict(), f, indent=2, ensure_ascii=False, default=str)


class DirectoryScanner(ABC):
    """
    目录扫描器抽象基类
    
    定义目录扫描的标准接口。
    """
    
    @abstractmethod
    async def scan(self, directory: str, **kwargs) -> ScanResult:
        """
        扫描目录
        
        Args:
            directory: 目录路径
            **kwargs: 其他参数
        
        Returns:
            扫描结果
        """
        pass
    
    @abstractmethod
    def get_supported_extensions(self) -> Set[str]:
        """获取支持的文件扩展名"""
        pass
    
    def is_supported_file(self, file_path: str) -> bool:
        """检查是否支持该文件"""
        ext = Path(file_path).suffix.lower().lstrip('.')
        return ext in self.get_supported_extensions()


class FileClassifier(ABC):
    """
    文件分类器抽象基类
    
    定义文件分类的标准接口。
    """
    
    @abstractmethod
    async def classify(self, file_info: FileInfo) -> FileInfo:
        """
        分类文件
        
        Args:
            file_info: 文件信息
        
        Returns:
            更新后的文件信息
        """
        pass
    
    @abstractmethod
    def add_rule(self, rule: ClassificationRule) -> None:
        """添加分类规则"""
        pass
    
    @abstractmethod
    def get_rules(self) -> List[ClassificationRule]:
        """获取所有分类规则"""
        pass
